package util;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

import computation.Geometry;

import primatives.PointND;
import ui.Window_MainApp;

public class epsNet_ReductionEditor extends JFrame
{
	final JFileChooser fc = new JFileChooser();
	
	private JLabel labelCloudSize;
	private JLabel labelReductionSize;
	
	private JTextField txtDimension;
	private JTextField txtEpsilon;
	private JTextField txtScale;

	private JButton btnLoadCloud;
	private JButton btnSetEpsilon;
	private JButton btnRunReduction;
	
	private ArrayList<PointND> cloud;
	
	private int nReductionSize;
	
	private int nDimension;
	private double dScale;
	private double dEpsilon;
	
	// TODO: all the text fields create a new numeric key adapter, perhaps create just one and get all the text fields to use it?
	public class NumericKeyAdapter extends KeyAdapter
	{
		public void keyTyped(KeyEvent e)
		{
			// eat any characters that are not digits (and some special characters like backspace)
			char c = e.getKeyChar();
            if (!((c==KeyEvent.VK_BACK_SPACE) || (c==KeyEvent.VK_DELETE) ||  (c== KeyEvent.VK_ENTER)  || (c == KeyEvent.VK_TAB) ||
            		(c==KeyEvent.VK_DECIMAL) || (c==KeyEvent.VK_PERIOD) || (c==KeyEvent.VK_MINUS) || (Character.isDigit(c)))) e.consume();
		}
	}
	
	public epsNet_ReductionEditor()
	{
		super("eps-Net Reduction");
		
		cloud = new ArrayList<PointND>();
		
		nReductionSize = 0;
		
		nDimension = 3;
		dScale = 1.0;
		dEpsilon = 0.01;
		
		setupUI();
		
		setVisible(true);
		pack();
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}
	
	public void setupUI()
	{
		labelCloudSize = new JLabel("Cloud Size: " + cloud.size());
		labelReductionSize = new JLabel("Reduction Size: " + nReductionSize);
		
		txtDimension = new JTextField(""+nDimension, 5);
		txtEpsilon = new JTextField(""+dEpsilon, 5);
		txtScale = new JTextField(""+dScale, 5);
		
		btnLoadCloud = new JButton("Load");
		btnSetEpsilon = new JButton("Set");
		btnRunReduction = new JButton("Reduce");
		
		txtDimension.addKeyListener(new NumericKeyAdapter());
		txtEpsilon.addKeyListener(new NumericKeyAdapter());
		txtScale.addKeyListener(new NumericKeyAdapter());
		
		btnLoadCloud.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { LoadPointCloud(); } });
		btnSetEpsilon.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setStatusLabel(); } });
		btnRunReduction.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ReducePointCloud(); } });
		
		this.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
		c.anchor = GridBagConstraints.WEST;
		
		c.gridx = 0;
		c.gridy = 0;
		add(btnLoadCloud, c);
		
		c.gridx = 0;
		c.gridy = 1;
		add(btnSetEpsilon, c);
		
		c.gridx = 0;
		c.gridy = 2;
		add(btnRunReduction, c);
		
		c.gridx = 0;
		c.gridy = 3;
		add(labelCloudSize, c);
		

		
		c.gridx = 1;
		c.gridy = 0;
		c.anchor = GridBagConstraints.WEST;
		add(new JLabel("Dimension: "), c);
		
		c.gridx = 2;
		c.gridy = 0;
		c.anchor = GridBagConstraints.EAST;
		add(txtDimension, c);

		c.gridx = 1;
		c.gridy = 1;
		c.anchor = GridBagConstraints.WEST;
		add(new JLabel("Epsilon: "), c);
		
		c.gridx = 2;
		c.gridy = 1;
		c.anchor = GridBagConstraints.EAST;
		add(txtEpsilon, c);

		c.gridx = 1;
		c.gridy = 2;
		c.anchor = GridBagConstraints.WEST;
		add(new JLabel("Scale: "), c);
		
		c.gridx = 2;
		c.gridy = 2;
		c.anchor = GridBagConstraints.EAST;
		add(txtScale, c);
		
		c.gridx = 2;
		c.gridy = 3;
		add(labelReductionSize, c);
	}
	
	public void setStatusLabel()
	{
		dEpsilon = Double.parseDouble(txtEpsilon.getText());
		dScale = Double.parseDouble(txtScale.getText()); 
		
		nReductionSize = Geometry.computeEps_DrawNumber(dScale, nDimension, dEpsilon);
		labelCloudSize.setText("Cloud Size: " + cloud.size());
		labelReductionSize.setText("Reduction Size: " + nReductionSize);
		
		pack();
	}
	
	public void LoadPointCloud()
	{
		// TODO: file filters for point clouds (aka, .txt)
        int returnVal = fc.showOpenDialog(epsNet_ReductionEditor.this);

        if (returnVal == JFileChooser.APPROVE_OPTION)
        {
            File file = fc.getSelectedFile();
            cloud = PointCloudReader.ReadFile(file.getAbsolutePath());
            
            setStatusLabel();
        }
	}
	
	public void ReducePointCloud()
	{
		ArrayList<PointND> reduced;
		
		System.out.println("eps-Net draws: " + nReductionSize);
		
		if (nReductionSize < cloud.size())
		{
			reduced = new ArrayList<PointND>(nReductionSize);
			Random rand = new Random(System.currentTimeMillis());
			for (int i = 0; i < nReductionSize; i++)
			{
				int index = rand.nextInt(cloud.size());
				PointND pt = cloud.get(index);
				reduced.add(pt);
			}
			
			// TODO: file filters for point clouds (aka, .txt)
            int returnVal = fc.showSaveDialog(epsNet_ReductionEditor.this);

            if (returnVal == JFileChooser.APPROVE_OPTION)
            {
                File file = fc.getSelectedFile();
                PointCloudWriter.WriteFile_PointND(file.getAbsolutePath(), reduced);
            }
		}
		else
		{
			System.out.println("Not enough inital vertices!");
		}
	}
	
	public static void main(String args[])
	{
		epsNet_ReductionEditor frame = new epsNet_ReductionEditor();
	}
	
}
